package com.kggs.springsnmp.utils;

import java.io.IOException;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.Null;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;
/**
 * WALK的方式获取值
 * @author jzj
 * @date 2020/7/30 15:23
 */
public class SnmpWalk {

  public static final int DEFAULT_VERSION = SnmpConstants.version2c;
  public static final String DEFAULT_PROTOCOL = "udp";
  public static final int DEFAULT_PORT = 161;
  public static final long DEFAULT_TIMEOUT = 3 * 1000L;
  public static final int DEFAULT_RETRY = 3;

  /**
   * 创建对象communityTarget
   *
   * @param ip
   * @param community
   * @return CommunityTarget
   */
  public static CommunityTarget createDefault(String ip, String community) {
    Address address = GenericAddress.parse(DEFAULT_PROTOCOL + ":" + ip + "/" + DEFAULT_PORT);
    CommunityTarget target = new CommunityTarget();
    target.setCommunity(new OctetString(community));
    target.setAddress(address);
    target.setVersion(DEFAULT_VERSION);
    // milliseconds
    target.setTimeout(DEFAULT_TIMEOUT);
    target.setRetries(DEFAULT_RETRY);
    return target;
  }

  /**
   * @param ip
   * @param community
   * @param targetOid
   */
  public static void snmpWalk(String ip, String community, String targetOid) {

    CommunityTarget target = SnmpGet.createDefault(ip, community);
    TransportMapping transport = null;
    Snmp snmp = null;
    try {
      transport = new DefaultUdpTransportMapping();
      snmp = new Snmp(transport);
      transport.listen();

      PDU pdu = new PDU();
      OID oid = new OID(targetOid);
      pdu.add(new VariableBinding(oid));

      boolean finished = false;
      System.out.println("----> demo start <----");
      while (!finished) {
        VariableBinding vb = null;
        ResponseEvent respEvent = snmp.getNext(pdu, target);

        PDU response = respEvent.getResponse();

        if (null == response) {
          System.out.println("responsePDU == null");
          finished = true;
          break;
        } else {
          vb = response.get(0);
        }
        // check finish
        finished = checkWalkFinished(oid, pdu, vb);
        if (!finished) {
          System.out.println("==== walk each vlaue :");
          System.out.println(vb.getOid() + " = " + vb.getVariable());

          // Set up the variable binding for the next entry.
          pdu.setRequestID(new Integer32(0));
          pdu.set(0, vb);
        } else {
          System.out.println("SNMP walk OID has finished.");
          snmp.close();
        }
      }
      System.out.println("----> demo end <----");
    } catch (Exception e) {
      e.printStackTrace();
      System.out.println("SNMP walk Exception: " + e);
    } finally {
      if (snmp != null) {
        try {
          snmp.close();
        } catch (IOException ex1) {
          snmp = null;
        }
      }
    }
  }

  /**
   * 1)responsePDU == null<br>
   * 2)responsePDU.getErrorStatus() != 0<br>
   * 3)responsePDU.get(0).getOid() == null<br>
   * 4)responsePDU.get(0).getOid().size() < targetOID.size()<br>
   * 5)targetOID.leftMostCompare(targetOID.size(),responsePDU.get(0).getOid()) !=0<br>
   * 6)Null.isExceptionSyntax(responsePDU.get(0).getVariable().getSyntax())<br>
   * 7)responsePDU.get(0).getOid().compareTo(targetOID) <= 0<br>
   *
   * @param targetOid
   * @param pdu
   * @param vb
   * @return
   */
  private static boolean checkWalkFinished(OID targetOid, PDU pdu, VariableBinding vb) {
    boolean finished = false;
    if (pdu.getErrorStatus() != 0) {
      System.out.println("[true] responsePDU.getErrorStatus() != 0 ");
      System.out.println(pdu.getErrorStatusText());
      finished = true;
    } else if (vb.getOid() == null) {
      System.out.println("[true] vb.getOid() == null");
      finished = true;
    } else if (vb.getOid().size() < targetOid.size()) {
      System.out.println("[true] vb.getOid().size() < targetOID.size()");
      finished = true;
    } else if (targetOid.leftMostCompare(targetOid.size(), vb.getOid()) != 0) {
      System.out.println("[true] targetOID.leftMostCompare() != 0");
      finished = true;
    } else if (Null.isExceptionSyntax(vb.getVariable().getSyntax())) {
      System.out.println("[true] Null.isExceptionSyntax(vb.getVariable().getSyntax())");
      finished = true;
    } else if (vb.getOid().compareTo(targetOid) <= 0) {
      System.out.println(
          "[true] Variable received is not " + "lexicographic successor of requested " + "one:");
      System.out.println(vb.toString() + " <= " + targetOid);
      finished = true;
    }
    return finished;
  }

  /** @param args */
  public static void main(String[] args) {
    String ip = "127.0.0.1";
    String community = "public";
    // 1.3.6.1.2.1.2.2.1.2
    String targetOid = ".1.3.6.1.2.1.25.2.3.1.2";
    SnmpWalk.snmpWalk(ip, community, targetOid);
  }
}
